package com.howie.hmvc.request;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import com.howie.hmvc.handler.IUploadProgressHandler;

/**
 * 处理文件上传
 * @author dhz
 */
public class MultipartRequest extends HttpServletRequestWrapper {

	private static DiskFileItemFactory factory;
	private static final String ENCODING = "UTF-8";
	private HttpServletRequest request;
	private Class<IUploadProgressHandler> uploadProgressHandler;
	private Map<String, List<String>> parameters = new HashMap<String, List<String>>();
	private Map<String, List<FileItem>> multipartFiles = new HashMap<String,List<FileItem>>();

	//最多只允许在内存中存储的数据,单位:字节
	private static final Integer FILE_MEM_MAX_SIZE = 1024 * 10;
	
	/**
	 * 构造函数
	 * @param request
	 * @throws FileUploadException 
	 * @throws UnsupportedEncodingException 
	 * @throws UIException 
	 */
	public MultipartRequest(HttpServletRequest request,Class<IUploadProgressHandler> uploadProgressHandler)throws Exception{
		super(request);
		if(factory == null){
			factory = new DiskFileItemFactory();
			//最多只允许在内存中存储的数据,单位:字节
			factory.setSizeThreshold(FILE_MEM_MAX_SIZE);
			//设置临时目录
			File tmpFile = new File(System.getProperty("java.io.tmpdir"));
			if(!tmpFile.exists()){
				tmpFile.mkdirs();
			}
			factory.setRepository(tmpFile);
		}
		this.request = request;
		this.uploadProgressHandler = uploadProgressHandler;
		this.processUpload();
	}

	/**
	 * 获取参数
	 */
	public String getParameter(String name){
		List<String> v = parameters.get(name);
		if (v != null && v.size() > 0) {
			return v.get(0);
		}
		return super.getParameter(name);
	}

	/**
	 * 获取参数
	 */
	public String[] getParameterValues(String name) {
		List<String> v = parameters.get(name);
		if (v != null && v.size() > 0) {
			return v.toArray(new String[v.size()]);
		}
		return null;
	}
	
	/**
	 * 获取文件
	 * @param name
	 * @return
	 */
	public FileItem getFile(String name) {
		List<FileItem> files = multipartFiles.get(name);
		if (files != null && files.size() > 0) {
			return files.get(0);
		}
		return null;
	}

	/**
	 * 获取文件
	 * @param name
	 * @return
	 */
	public FileItem[] getFiles(String name) {
		List<FileItem> files = multipartFiles.get(name);
		return files == null ? null : files.toArray(new FileItem[files.size()]);
	}
	
	/*
	 * 执行上传文件
	 * @throws FileUploadException
	 * @throws UnsupportedEncodingException
	 */
	private void processUpload() throws Exception{
		ServletFileUpload upload = new ServletFileUpload(factory);
		//设置文件上传进度监听器
		if(uploadProgressHandler != null){
			IUploadProgressHandler progress = uploadProgressHandler.newInstance();
			progress.setRequest(request);
			upload.setProgressListener(progress);
		}
		List<?> fileItems = upload.parseRequest(request);
		for(Object obj : fileItems){
			FileItem item = (FileItem)obj;
			//判断是form表单域还是上传文件file域
			if (item.isFormField()) {
				processNormalFormField(item);
			} else {
				processFileField(item);
			}
		}
	}
	
	/*
	 * 处理文件域
	 * @param item
	 */
	private void processFileField(FileItem item){
		String fieldName = item.getFieldName();
		List<FileItem> values = multipartFiles.get(fieldName);
		if(values == null){
			values = new ArrayList<FileItem>();
			multipartFiles.put(fieldName,values);
		}
		values.add(StringUtils.isBlank(item.getName()) ? null : item);
	}

	/*
	 * 处理表单域
	 * @param item
	 * @throws UnsupportedEncodingException
	 */
	private void processNormalFormField(FileItem item) throws UnsupportedEncodingException{
		String fieldName = item.getFieldName();
		List<String> values = parameters.get(fieldName);
		if (values == null) {
			values = new ArrayList<String>();
			parameters.put(fieldName,values);
		}
		values.add(new String(item.get(),ENCODING));
	}

}
